--[[
Author:  Javek
ReleaseDate: 3-24-2007
--]]


GnomeCruncher = AceLibrary("AceAddon-2.0"):new("AceConsole-2.0","AceDB-2.0","AceDebug-2.0")

function GnomeCruncher:OnInitialize()
    -- Called when the addon is loaded
end

function GnomeCruncher:OnEnable()
    -- Called when the addon is enabled
    
	self:SetDebugging(false)
--	self:SetDebugLevel(3)
	self:RegisterDB("GnomeCruncherDB", "GnomeCruncherDBPC")
	self:RegisterDefaults("char", {
	xpos = 400,
	ypos = 400,
	showing = true,
	width = 150,
	vertDir = true,
	horizDir = true,
	resR = 0.2,
	resG = 0.6,
	resB = 1
	})
	--[[
		vertDir	true is up
		horizDir true is left
		resX are the colors for results
	--]]
	local options = { 
    type='group',
    args = {
	    show = {
	        	type = 'toggle',
	        	name = 'Show/Hide GnomeCruncher',
	        	desc = 'Shows or hides the calculator',
				get = 'isShown',
				set = 'show',
				map = {[false] = 'Hidden',[true] = 'Showing'}
	        	},
	    reset = {
	        	type = 'execute',
	        	name = "Resets GnomeCruncher's position",
	        	desc = 'Resets the calculator position',
	        	func = 'reset'
	        	},
	    width = {
	    		type = 'range',
	    		name = 'GnomeCruncher Width',
	    		desc = 'Sets the width of the calculator',
	    		get = 'getWidth',
	    		set = 'setWidth',
	    		min = 10,
	    		max = 1000,
	    		step = 1
	    		},
	    vertical = {
	    		type = 'toggle',
	    		name = 'Switches the vertical direction.',
	    		desc = 'Toggles the direction results grow in',
	    		get = 'getVertical',
	    		set = 'setVertical',
	    		map = {[false] = 'Down',[true]='Up'}
	    		},
	    side = {
	    		type = 'toggle',
	    		name = 'Toggles which side of the icon the bars line on.',
	    		desc = 'Toggles whether bars line up on the left or right',
	    		get = 'getHorizontal',
	    		set = 'setHorizontal',
	    		map = {[false] = 'Right',[true]='Left'}
	    		},
	    resultColor = {
	    		type = 'color',
	    		name = 'Results Text Color',
	    		desc = 'Sets the result text color',
	    		get = 'getResultColor',
	    		set = 'setResultColor',
	    		hasAlpha = false
	    		},
	    help = {
	    		type = 'execute',
	    		name = 'GnomeCruncher Help',
	    		desc = 'Displays GnomeCruncher Instructions.',
	    		func = 'help'
	    		}	    		
    }}    
        
    self:RegisterChatCommand({"/gnomecruncher"}, options)
	self.AceOO = AceLibrary("AceOO-2.0")


	self.lastAns = 0
	self.newEntry = true
	self.result = nil
	self.resultColorText = nil
	
	self.substitute = {
	["e"] = "math.exp(1)",
	["pi"] = "math.pi",
	["ans"] = "GnomeCruncher.lastAns",
	["ln"] = "log",
	["log"] = "log10"
	}
	self:GuiInit()
	self:updateResultColorText()
	self:Debug("GnomeCruncher Initialized")
end

function GnomeCruncher:OnDisable()
    -- Called when the addon is disabled
end

function GnomeCruncher:newChar()
	--arg1 = char
	if self.newEntry then
		self:Debug("FIRST CHAR")	
		for i,j in pairs({"+","-","*","/","^"}) do
			if arg1 == j then
				self.entryFrame:SetText("ans"..arg1)
			end
		end
	end
	self.newEntry = false	
end

function GnomeCruncher:execute()
	--Execute Code and add result frame
	
	--Get Frame
	local f = nil
	local n = table.getn(self.frameStack)
	if n > 0 then
		f = self.frameStack[n]
		table.remove(self.frameStack)
	else
		f = CreateFrame("EditBox",nil,self.mainFrame,"GnomeCruncherResultBoxTemplate")	
	end
	
	-- Parse Text
	local origText = self.entryFrame:GetText()
	local text = origText:lower()
	self.entryFrame:SetText("")
	self.newEntry = true
	-- Make text substitutions
	for pattern,value in pairs(self.substitute) do
		self:Debug("Searching for "..pattern)
		local again = true
		local loops = 0
		local lastEnd = 1
		while again and loops < 100 do
			local st,en = string.find(text,pattern,lastEnd)
			if st == nil then
				self:Debug("Not Found")
				again = false
			else
				self:Debug(string.format("Found pattern %d to %d",st,en))
				text = text:sub(1,st-1)..value..text:sub(en+1,-1)
				lastEnd = st + strlen(value) + 1
			end
			loops = loops + 1
		end
	end
	
	-- Execute Calculation
	self:Debug("text: "..text)
	local resultFunc = loadstring("GnomeCruncher.result = "..text)
	local result
	if resultFunc == nil then
		result = self:errorText()
	else
		if pcall(resultFunc) then
			--No Errors
			if GnomeCruncher.result == nil then
				result = self:errorText()
			else
				self.lastAns = GnomeCruncher.result
				result = self.resultColorText..GnomeCruncher.result
			end			
		else
			result = self:errorText()
		end
	end

	f:SetText(origText.." = "..result)
	
	-- Add this frame to the list and update position
	table.insert(self.resultFrames,f)
	local n = table.getn(self.resultFrames)
	self:updateFramePosition(n)
	self:updateFramePosition(n-1)
	f:Show()
end

function GnomeCruncher:errorText()
	return "|cFFFF0000Error!"
end

function GnomeCruncher:removeResult(removeFrame)
	self:Debug("Removing Result")
	for n,f in pairs(self.resultFrames) do
		if f == removeFrame then
			f:ClearAllPoints()
			f:SetText("")
			f:Hide()
			table.insert(self.frameStack,f)
			table.remove(self.resultFrames,n)
			self:updateFramePosition(n-1)
		end
	end
end


--Commands
function GnomeCruncher:isShown()
	return self.mainFrame:IsVisible()
end

function GnomeCruncher:show(state)
	if state then
		self.mainFrame:Show()
		self.db.char.showing = true
	else
		self.mainFrame:Hide()
		self.db.char.showing = false
	end
end

function GnomeCruncher:getVertical()
	return self.db.char.vertDir
end
function GnomeCruncher:setVertical(x)
	self.db.char.vertDir = x
	for i = table.getn(self.resultFrames),1,-1 do
		self:updateFramePosition(i)
	end
end
function GnomeCruncher:getHorizontal()
	return self.db.char.horizDir
end
function GnomeCruncher:setHorizontal(x)
	self.db.char.horizDir = x
	self.entryFrame:ClearAllPoints()
	if x then
		--Left
		self.entryFrame:SetPoint("TOPRIGHT",self.mainFrame,"TOPLEFT",0,3)
	else
		self.entryFrame:SetPoint("TOPLEFT",self.mainFrame,"TOPRIGHT",0,3)
	end
	for i = table.getn(self.resultFrames),1,-1 do
		self:updateFramePosition(i)
	end	
end

function GnomeCruncher:getWidth()
	return self.db.char.width
end
function GnomeCruncher:setWidth(x)
	self.db.char.width = x
	self.entryFrame:SetWidth(x)
end

function GnomeCruncher:setResultColor(r,g,b)
	self:LevelDebug(3,"ResultColor("..r..","..g..","..b..")")
	self.db.char.resR = r
	self.db.char.resG = g
	self.db.char.resB = b
	self:updateResultColorText()
end
function GnomeCruncher:getResultColor()
	return self.db.char.resR,self.db.char.resG,self.db.char.resB
end
function GnomeCruncher:updateResultColorText()
	--3CA4DB
	self.resultColorText = ("|c%02x%02x%02x%02x"):format(255,self.db.char.resR*255,self.db.char.resG*255,self.db.char.resB*255)
	self.resultColorText:upper()
	self:LevelDebug(3,"New Color Text: "..self.resultColorText:sub(3,-1).."TestText")
--	self.resultColorText = string.format("|%s%s%s",self.db.char.resR, self.db.char.resG, self.db.char.resB)
end

function GnomeCruncher:help()
	self:Print([[Instructions:
	Pressing Enter performs a calculation.
	You may use parenthesis to group math operations.
	Addition: +  Subtraction: -  Multiplication: *  Division: /  Exponents: ^
	Various functions such as cos(), sin(),tan(),ln(),log(),acos() are available as well as the constants pi and e.
	The word ans is replaced with the last calculated answer.
	Various configuration options can be set with /gnomecruncher]])
end
